/* Author	: Manish YM
 * Date		: 30/07/2009
 * Description	: Explains how to run kernel threads. Taken from chapter 3 of Essential Device Drivers book.
 */


static DECLARE_WAIT_QUEUE_HEAD (myevent_waitqueue);
/* Wait queue is used to put a kernel thread into waiting state and then wake it up from somewhere else
 * This is the handle we can later use to start the thread again
 */

rwlock_t myevent_lock ; 
/* Lock to prevent race conditions. This is required because the variable myevent_id is updated from some other thread
 * and read here.
 */

extern unsigned int myevent_id ; 
/* Holds ID of troubled data structure. Here in this example, the kernel will run a userspace program when 
 * some data structure which is monitored by some process is having trouble. We put ID of the data structure in this variable 
 */

static int mykthread (void *unused)
{
    unsigned int event_id = 0;
    DECLARE_WAITQUEUE(wait, current);
    /*LATER*/
    daemonize ("mykthread") ;
    /* Creates a kernel thread daemon*/

    allow_signal (SIGKILL);
    /* Allows delivery of sigkill. This will put all pending signal into variable current. We can check if some signals are 
     * pending and get killed if sigkill is delivered.
     */

    add_wait_queue (&myevent_waitqueue, &wait);
    /* Adds current thread to waitqueue
     */

    for(;;)
    {
	set_current_state( TASK_INTERRUPTIBLE ) ;
	/*
	 * INTERRUPTIBLE tasks can be run when some event occurs
	 */
	schedule();
	/*
	 * gives up cpu to wait for and event
	 */
	if (signal_pending (current))
	    break;
	/*
	 * Die if sigkill is delivered.
	 */
	read_lock (&myevent_lock);
	if (myevent_id)
	{
	    event_id = myenvent_id ;
	    read_unlock (&myevent_lock) ;
	    run_umode_handler(event_id) ;
	}
	else
	{
	    read_unlock (&myevent_lock);
	}
    }

    set_current_state (TASK_RUNNING) ;
    remove_wait_queue (&myevent_waitqueue);
    return 0;
}
	    
		
	
	    
	
	
    
    
